package com.sh.data.engine.domain.util;

import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.sh.data.engine.domain.base.model.PageResult;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 属性拷贝工具类
 *
 * @author: mengzheng.mhc
 * @date: 2024/6/3 11:29
 */
@Slf4j
public class ConvertUtil {

    /**
     * 对象属性拷贝
     *
     * @param sourceObj   源对象
     * @param targetClass 目标对象
     * @param <T>         目标对象泛型
     * @return 拷贝后的对象
     */
    public static <T> T copyProperties(Object sourceObj, Class<T> targetClass) {
        if (sourceObj == null || targetClass == null) {
            return null;
        }
        try {
            T targetObj = targetClass.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(sourceObj, targetObj);
            return targetObj;
        } catch (Exception e) {
            log.error(
                "copy bean error, from {} to {}",
                sourceObj.getClass().getSimpleName(),
                targetClass.getSimpleName(),
                e);
        }
        return null;
    }

    /**
     * 对象属性拷贝
     *
     * @param sourceObj        源对象
     * @param targetClass      目标对象
     * @param ignoreProperties 忽略的属性
     * @param <T>              目标对象泛型
     * @return 拷贝后的对象
     */
    public static <T> T copyProperties(
        Object sourceObj, Class<T> targetClass, String... ignoreProperties) {
        if (sourceObj == null || targetClass == null) {
            return null;
        }
        try {
            T targetObj = targetClass.getDeclaredConstructor().newInstance();
            BeanUtils.copyProperties(sourceObj, targetObj, ignoreProperties);
            return targetObj;
        } catch (Exception e) {
            log.error(
                "copy bean error, from {} to {}",
                sourceObj.getClass().getSimpleName(),
                targetClass.getSimpleName(),
                e);
        }
        return null;
    }

    /**
     * List<?>泛型擦除与替换
     *
     * @param sourceObjList 原对象List
     * @param targetClass   目标类型
     * @param <T>           目标泛型
     * @return List<T>
     */
    public static <T> List<T> copyProperties(List<?> sourceObjList, Class<T> targetClass) {
        if (sourceObjList == null || sourceObjList.isEmpty() || targetClass == null) {
            return Collections.emptyList();
        }

        return sourceObjList.stream()
            .map(e -> copyProperties(e, targetClass))
            .filter(Objects::nonNull)
            .collect(Collectors.toList());
    }

    /**
     * PageResult泛型擦除与替换
     *
     * @param page 原分页对象
     * @param v    目标泛型
     * @param <T>  待擦除泛型
     * @param <V>  替换的泛型
     * @return V泛型的PageResult
     */
    public static <T, V> PageResult<V> convertPageInfo(PageResult<T> page, Class<V> v) {
        if (null == page || null == v) {
            return null;
        }

        PageResult<V> vPageInfo = new PageResult<>();

        BeanUtils.copyProperties(page, vPageInfo);

        List<T> tList = page.getResult();

        List<V> vList = new ArrayList<>();

        if (CollectionUtils.isNotEmpty(tList)) {
            for (T t : tList) {
                V targetPageInfo = ConvertUtil.copyProperties(t, v);
                vList.add(targetPageInfo);
            }
        }

        vPageInfo.setResult(vList);

        return vPageInfo;
    }

    /**
     * 类型转换
     *
     * @param input  源对象
     * @param mapper 转换Function
     * @param <T>    源对象Class
     * @param <R>    目标对象Class
     * @return 目标对象
     */
    public static <T, R> R convert(T input, Function<? super T, ? extends R> mapper) {
        return mapper.apply(input);
    }

    /**
     * List泛型转换
     *
     * @param input  源对象List
     * @param mapper 转换Function
     * @param <T>    源对象Class
     * @param <R>    目标对象Class
     * @return 目标对象List
     */
    public static <T, R> List<R> convert(List<T> input, Function<? super T, ? extends R> mapper) {
        return input.stream().map(mapper).collect(Collectors.toList());
    }

    /**
     * PageResult泛型转换
     *
     * <p>分页转换，可以使用分页对象调用.convert()方法
     *
     * @param input  源对象PageResult
     * @param mapper 转换Function
     * @param <T>    源对象Class
     * @param <R>    目标对象Class
     * @return 目标对象PageResult
     * @see com.sh.data.engine.domain.base.model.PageResult#convert(java.util.function.Function)
     */
    public static <T, R> PageResult<R> convert(
        PageResult<T> input, Function<? super T, ? extends R> mapper) {
        List<R> collect = input.getResult().stream().map(mapper).collect(Collectors.toList());
        PageResult<R> rPageResult = new PageResult<>();
        rPageResult.setResult(collect);
        rPageResult.setPageNum(input.getPageNum());
        rPageResult.setPageSize(input.getPageSize());
        rPageResult.setTotalPages(input.getTotalPages());
        rPageResult.setTotalElements(input.getTotalElements());
        return rPageResult;
    }
}
